#                          -*- Perl -*-
# Copyright (C) 2011  anon1007
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#

require 5.005;

use English;
use FileHandle;
use Jcode;
use FreePWING::FPWUtils::FPWParser;
use utf8;

sub BEGIN {
	unshift @INC, $FindBin::Bin;

}

use JDCommon;
use JDFormatter;
use FPprinter;

if (@ARGV == 0) {
  $source_directory = '.';
} else {
  $source_directory = shift;
}

print "src:$source_directory";
# Читаем конфиги yarxi
my $config = read_config_file("$source_directory/config/yarxi.conf");

if ( $config->{'cur_trans_type'} ) {
    JDFormatter::set_cur_trans_type( $config->{'cur_trans_type'} );
}
$JDPrinterC::use_italic = 1;

$readme_file_name = 'README.PKG';


#
# 各出力ファイルを開く。
#
initialize_fpwparser('text' => \$fpwtext,
		     'heading' => \$fpwheading,
		     'word2' => \$fpwword2,
		     'menu' => \$fpwmenu,
		     'copyright' => \$fpwcopyright);

#
# копирайты
#
if (!$fpwmenu->add_reference_start()
    || !$fpwmenu->add_text(jcode("Ｙａｒｘｉ辞書について", "utf-8")->euc)
    || !$fpwmenu->add_reference_end("readme1")
    || !$fpwmenu->add_newline()
    || !$fpwmenu->add_reference_start()
    || !$fpwmenu->add_text(jcode("FreePWING 版について", "utf-8")->euc)
    || !$fpwmenu->add_reference_end("readme2")
    || !$fpwmenu->add_newline()) {
  fpw_error($fpwmenu);
}
if (!$fpwmenu->new_context()
    || !$fpwmenu->add_tag("readme1")) {
  fpw_error($fpwmenu);
}

#
# README の登録
#
print "Reading README file...\n";
$handle = FileHandle->new();
if (!$handle->open("$readme_file_name", 'r')) {
  die "$PROGRAM_NAME: failed to open the file, $ERRNO: $readme_file_name\n";
}

while ($_ = $handle->getline()) {
  s/\r?\n?$//;
  if (!$fpwmenu->add_text($_)
      || !$fpwmenu->add_newline()) {
    fpw_error($fpwmenu);
  }
  if (!$fpwcopyright->add_text($_)
      || !$fpwcopyright->add_newline()) {
    fpw_error($fpwcopyright);
  }
}
$handle->close();
print " done.\n";

#
# README.PKG の登録
#
print "Reading README.PKG file...\n";
$handle = FileHandle->new();
if (!$handle->open("README.PKG", 'r')) {
  die "$PROGRAM_NAME: failed to open the file, $ERRNO: README.PKG\n";
}
if (!$fpwmenu->new_context()
    || !$fpwmenu->add_tag("readme2")) {
  fpw_error($fpwmenu);
}
while ($_ = $handle->getline()) {
  s/\r?\n?$//;
  if (!$fpwmenu->add_text($_)
      || !$fpwmenu->add_newline()) {
  fpw_error($fpwmenu);
  }
}
$handle->close();
print " done.\n";

###
### yarxi
###

sub article {
	my ($num) = @_;
	( $num eq int($num) ) or fail;

	JDCommon::cleanup();

	# Формирование статьи
	my $dom = format_article($num);
	if ( !$dom ) { # Нет такой статьи
		return "";
	}

	# так как  форматер лень переделывать чтобы взять  оны и куны,
	# берём данные из базы
	my $row = fetch_kanji_full($num);
	return undef if !$row; # Нет такой статьи


	$key = $dom->{'main_kanji'};
	$key =~ /K\d{4}(.)/;
	$key = $1;

	if (!$fpwtext->new_entry()) {
	    fpw_error($fpwtext)
	}
	if (!$fpwheading->new_entry()) {
	    fpw_error($fpwheading)
	}

	$text_position = $fpwtext->entry_position();
	$heading_position = $fpwheading->entry_position();
	# kanji entry
	if (!$fpwword2->add_entry(jj($key),
				  $heading_position,
				  $heading_file_name, $text_position,
				  $text_file_name)) {
	    die "$PROGRAM_NAME: " . $fpwword2->error_message() . "\n";
	}

	# on entry
	{
	    my $onyomi = $row->{'Onyomi'};
	    $onyomi =~ s/[*_()\-]//g; # kill all symb
	    my @onyomi_spl = split /,/, $onyomi;
	    foreach my $s ( @onyomi_spl ) {
		if ($s) {
		    if (!$fpwword2->add_entry(jj(kana(uc $s, "")),
					      $heading_position,
					      $heading_file_name, $text_position,
					      $text_file_name)) {
			die "$PROGRAM_NAME: " . $fpwword2->error_message() . "\n";
		    }
		}
	    }
	}

	# kun entry
	{
	    my $k = $row->{'Kunyomi'};
	    my @line_split = split /\|/, $k;
	    my $k = (shift @line_split or "");

	    $k !~ /\*\*[^a-z ]/ or fail;
	    # Небольшое переформатирование
	    # Убираем пробелы перед кунами, записанными катаканой
	    $k =~ s/(^|\*) +([A-Z])/$1$2/g;
	    # Убираем пробелы и после.
	    $k =~ s/ +\*/\*/g;
	    # # Заменяем "**word*" на "*word_*". Я хочу применять цвет к готовому слову.
	    # $kunyomi =~ s/\*\*([^\*]+)/*$1_/g;

	    ## Заменяем "*/*word" на */word" чтобы на этом месте не обрывалась цепочка.
	    $k =~ s/\*([\/=&])\*/\*$1/g;

	    # Добавляем символ ! перед кодовыми обозначениями, чтобы не перепутать их со словами.
	    $k =~ s/\*(V[TI2]|Q[1237]|L1)(?=\*|$)/\*!$1/g;
	    my @kunyomi_spl1 = split(/\*/, $k); # Разделяем по звёздочке *

	    my @kun_chains = (); # массив для результатов
	    my @kun_arr = (); # Массив для текущей цепочки

	    while ( @kunyomi_spl1 ) {
		my $chunk = shift @kunyomi_spl1; # берём очередной элемент

		if ( $chunk =~ /^[a-zA-Z]/ ) {  # Если начинается с буквы
		    # Это новый кун!
		    if (!$fpwword2->add_entry(jj(kana(lc $chunk, "")),
					      $heading_position,
					      $heading_file_name, $text_position,
					      $text_file_name)) {
			die "$PROGRAM_NAME: " . $fpwword2->error_message() . "\n";
		    }

		}
	    }
	}

	$heading = $key;

	$heading = $key." ".flat_text( $dom->{'rusnick'} );
	$heading .= flat_text( $dom->{'utility'} ) if $dom->{'utility'};

	if (!$fpwheading->add_text(jcode($heading, "utf-8")->euc)) {
	    fpw_error($fpwheading)
	}

	my $kw = $key;
	$kw .= "  ";
	$kw .= flat_text( $dom->{'rusnick'} );

	# keyword
	$tagname = "a".base_16(jj($key));
	if (!$fpwtext->add_entry_tag($tagname)
	    || !$fpwtext->add_keyword_start()
	    || !$fpwtext->add_text(jj($kw))
	    || !$fpwtext->add_keyword_end()
	    || !$fpwtext->add_newline()) {
	    fpw_error($fpwtext);
	}

	# "Рендеринг" статьи
	my $out = print_article($dom);
	$out .= "\n";

	foreach my $line ( split /\n/, $out ) {
	    
	    # split articles by line and print
	    if (!$fpwtext->add_indent_level(2)) {
		fpw_error($fpwtext);
	    }

	    my $fm = 0;
	    # parse printed text
	    for (my $i = 0; $i < length($line); $i++) {
	    	my $ch = substr ($line, $i, 1);
		if ($ch eq "\001") {
		    if ($fm == 1 && !$fpwtext->add_font_end()) {
		    	fpw_error($fpwtext);
		    }
		    if (!$fpwtext->add_font_start('bold')) {
		    	fpw_error($fpwtext);
		    }
		    $fm = 1;
		} elsif ($ch eq "\002") {
		    if ($fm == 1 && !$fpwtext->add_font_end()) {
		    	fpw_error($fpwtext);
		    }
		    if (!$fpwtext->add_font_start('italic')) {
		    	fpw_error($fpwtext);
		    }
		    $fm = 1;
		} elsif ($ch eq "\x10") {
		    if ($fm ==1 && !$fpwtext->add_font_end()) {
		    	fpw_error($fpwtext);
		    }
		    $fm = 0;
		} elsif ($ch =~/\p{InCJKUnifiedIdeographs}/) {
	    	    if ($ch ne $key) {
	    		my $tag = "a".base_16(jj($ch));
	    		if (!$fpwtext->add_reference_start()
	    		    || !$fpwtext->add_text(jj($ch))
	    		    || !$fpwtext->add_reference_end($tag)) {
	    		    fpw_error($fpwtext);
	    		}
	    	    } else {
	    		if (!$fpwtext->add_text(jj($ch))) {
	    		    fpw_error($fpwtext);
	    		}
	    	    }
	    	} else {
	    	    if (!$fpwtext->add_text(jj($ch))) {
	    		fpw_error($fpwtext);
	    	    }
	    	}
	    }
	    if ($fm ==1 && !$fpwtext->add_font_end()) {
		fpw_error($fpwtext);
	    }
	    $fm = 0;
    
	    if (!$fpwtext->add_newline()) {
	    	fpw_error($fpwtext);
	    }
	}

	$dom = undef; # Удаляем объекты
	$kw = undef;
	$out = undef;
	return 1;
}

sub tango
{
	my ($num) = @_;

	( $num ) or fail;
	( $num eq int($num) ) or fail;

	JDCommon::cleanup();

	my $tango_obj = fetch_tango_full($num);
	return undef if !$tango_obj;
	$tango_obj = parse_tan($tango_obj);

	my $key = flat_text($tango_obj->{'word'});
	# format_tango_alone
	my $line_table = new_dom_object( 'htable', "Tango line" );
	$line_table->{'spacing'} = 2;
	$line_table->{'left'} = format_tango_word_and_transcr( $tango_obj );
	$line_table->{'right'} = format_russian_column( $tango_obj->{'russian'} );

	# format
	my $out = print_object($line_table);

	if (!$fpwtext->new_entry()) {
	    fpw_error($fpwtext)
	}

	if (!$fpwheading->new_entry()) {
	    fpw_error($fpwheading)
	}

	$text_position = $fpwtext->entry_position();
	$heading_position = $fpwheading->entry_position();
	if (!$fpwword2->add_entry(jj($key),
				  $heading_position,
				  $heading_file_name, $text_position,
				  $text_file_name)) {
	    die "$PROGRAM_NAME: " . $fpwword2->error_message() . "\n";
	}

	# hiragana reading
	foreach my $r ( @{$tango_obj->{'readings'}} ) {
	    my $transcr = '';
	    # may be force to katakana?
	    if (defined $tango_obj->{'force_katakana'} || $r->{'text'} =~ /(v)(y?[iueo])/i ||
		$r->{'text'} =~ /(tu)|(tso)|(HU)|(SI)/i) {
		$transcr = kana( uc $r->{'text'}, 'katakana');
	    }
	    elsif ( defined $tango_obj->{'force_hiragana'} ) {
		$transcr = kana(lc $r->{'text'}, 'hiragana');
	    }
	    else { # default
		$transcr = kana(lc $r->{'text'}, "");
	    }

	    if (!$fpwword2->add_entry(jj($transcr),
				      $heading_position,
				      $heading_file_name, $text_position,
				      $text_file_name)) {
		die "$PROGRAM_NAME: " . $fpwword2->error_message() . "\n";
	    }
	}

	my @lines = split /\n/, $out;
	my $heading = $lines[0];
	# text before ";" only
	$heading =~ s/^(.*?);.*/$1/;
	# kill font formating
	$heading =~ s/[\001\002\x10]//g;
	if (!$fpwheading->add_text(jcode($heading, "utf-8")->euc)) {
	    fpw_error($fpwheading)
	}
	
	# keyword same as heading
	# $tagname = "a".base_16(jj($key));
	if (#!$fpwtext->add_entry_tag($tagname)
	    !$fpwtext->add_keyword_start()
	    || !$fpwtext->add_text(jj($heading))
	    || !$fpwtext->add_keyword_end()
	    || !$fpwtext->add_newline()) {
	    fpw_error($fpwtext);
	}

	foreach my $line ( @lines ) {
	    
	    # split articles by line and print
	    if (!$fpwtext->add_indent_level(2)) {
		fpw_error($fpwtext);
	    }

	    my $fm = 0;
	    # parse printed text
	    for (my $i = 0; $i < length($line); $i++) {
	    	my $ch = substr ($line, $i, 1);
		if ($ch eq "\001") {
		    if ($fm == 1 && !$fpwtext->add_font_end()) {
		    	fpw_error($fpwtext);
		    }
		    if (!$fpwtext->add_font_start('bold')) {
		    	fpw_error($fpwtext);
		    }
		    $fm = 1;
		} elsif ($ch eq "\002") {
		    if ($fm == 1 && !$fpwtext->add_font_end()) {
		    	fpw_error($fpwtext);
		    }
		    if (!$fpwtext->add_font_start('italic')) {
		    	fpw_error($fpwtext);
		    }
		    $fm = 1;
		} elsif ($ch eq "\x10") {
		    if ($fm ==1 && !$fpwtext->add_font_end()) {
		    	fpw_error($fpwtext);
		    }
		    $fm = 0;
		} elsif ($ch =~/\p{InCJKUnifiedIdeographs}/) {
		    my $tag = "a".base_16(jj($ch));
		    if (!$fpwtext->add_reference_start()
			|| !$fpwtext->add_text(jj($ch))
			|| !$fpwtext->add_reference_end($tag)) {
			fpw_error($fpwtext);
	    	    }
	    	} else {
	    	    if (!$fpwtext->add_text(jj($ch))) {
	    		fpw_error($fpwtext);
	    	    }
	    	}
	    }
	    if ($fm ==1 && !$fpwtext->add_font_end()) {
		fpw_error($fpwtext);
	    }
	    $fm = 0;
    
	    if (!$fpwtext->add_newline()) {
	    	fpw_error($fpwtext);
	    }
	}

	$out = undef;
	$tango_obj = undef;
	$line_table = undef;
	return 1;
}

my $start_time = time();
my $i = 1;
print "Make articles:\n";
## go ##
# eval {
    while (article($i)) {
    	print STDERR "." if ( $i % 15 == 0 );
    	print STDERR "$i" if ( $i % 1000 == 0 );
    	$i++;
    };
# };

print STDERR "\n done in ".(time - $start_time)." seconds. Total $i.\n";

my $start_time = time();
$i = 1;
print "Make tango:\n";
# eval {
     while (tango($i)) {
 	print STDERR "." if ( $i % 20 == 0 );
 	print STDERR "$i" if ( $i % 1000 == 0 );
 	$i++;
     };
# };
 print STDERR "\n done in ".(time - $start_time)." seconds. Total $i.\n";


#
# 各出力ファイルを閉じる。
#
finalize_fpwparser('text' => \$fpwtext,
		   'heading' => \$fpwheading,
		   'word2' => \$fpwword2,
		   'menu' => \$fpwmenu,
		   'copyright' => \$fpwcopyright);

###
### subroutines
###

#
# 書式:
#       base_16(strings)
# 戻り値:
#       文字列 strings の各バイトを a から p の 16 文字 2 桁にエンコード
#       して返す。
#
sub base_16 {
  my(@temp_char) = split(//, $_[0]);
  my(@output);
  my($loop) = 0;
  do {
    $one_char_code = ord($temp_char[$loop]);
    $code_high = int($one_char_code / 16);
    $code_low = $one_char_code - $code_high * 16;
    $output[$loop] = chr($code_high + ord('a')) . chr($code_low + ord('a'));
    $loop++;
  } until $temp_char[$loop] eq "";
  return join('', @output);
}

# utf-8 -> euc
sub jj {
    my ($txt) = @_;
    return jcode($txt, "utf-8")->euc;
}

#
# エラーメッセージの出力
#
sub fpw_error {
  my($obj) = $_[0];
  print "$_\n";
  die "$PROGRAM_NAME: " . $obj->error_message() . "\n";
}
